package TEC;

/*
* 已知问题，offset指令偏移量问题
* */

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CodeTable {
    private String Code[][] = {
            {"ADD", "00", "R_2"},
            {"SUB", "01", "R_2"},
            {"AND", "02", "R_2"},
            {"CMP", "03", "R_2"},
            {"XOR", "04", "R_2"},
            {"TEST", "05", "R_2"},
            {"OR", "06", "R_2"},
            {"MVRR", "07", "R_2"},
            {"DEC", "08", "R_1"},
            {"INC", "09", "R_1"},
            {"SHL", "0A", "R_1"},
            {"SHR", "0B", "R_1"},
            {"JR", "41", "OFFSET"},
            {"JRC", "44", "OFFSET"},
            {"JRNC", "45", "OFFSET"},
            {"JRZ", "46", "OFFSET"},
            {"JRNZ", "47", "OFFSET"},
            {"JMPA", "80", "OFFSET"},
            {"IN", "82", "PORT"},
            {"PUSH", "85", "R_1"},
            {"OUT", "86", "PORT"},
            {"POP", "87", "R_1"},
            {"MVRD", "88", "R_1"},
            {"CALA", "CE", "OFFSET"},
            {"EI", "6E", "NONE"},
            {"DI", "6F", "NONE"},
            {"RET", "8F", "NONE"},
            {"IRET", "EF", "NONE"}
    };

    public String getCode(String Order) {
        for (String[] OneCode : Code) {
            if (Order.equalsIgnoreCase(OneCode[0])) {
                return OneCode[1];
            }
        }
        return "";
    }

    public String[] getOrder(String code) {
        for (String[] OneCode : Code) {
            if (code.equalsIgnoreCase(OneCode[1])) {
                return OneCode;
            }
        }
        return null;
    }

    public String getCodeWithTwoParameter(String Order) {
        StringBuilder res = new StringBuilder();
        String order = Order.split(" ")[0];
        res.append(getCode(order));
        String R1 = Order.split(" ")[1].split(",")[0];
        String R2 = Order.split(" ")[1].split(",")[1];
        res.append(Integer.toHexString(Integer.parseInt(R1.substring(1))));
        res.append(Integer.toHexString(Integer.parseInt(R2.substring(1))));
        return res.toString();
    }

    public String getCodeWithOneParameter(String Order) {
        StringBuilder res = new StringBuilder();
        String order = Order.split(" ")[0];
        res.append(getCode(order));
        res.append(Integer.toHexString(Integer.parseInt(Order.split(" ")[1].substring(1))));
        return res.toString();
    }

    public String getCodeOfOffset(String Order, int pc) {
        int sr = Integer.parseInt(Order.split(" ")[1], 16);
        if (pc / 256 == sr / 256) {
            StringBuilder res = new StringBuilder();
            String order = Order.split(" ")[0];
            res.append(getCode(order));
            int offset = ((sr & 0xff) - (pc & 0xff) - 1) & 0xff;
            res.append(Integer.toHexString(offset));
            return res.toString();
        } else {
            return "";
        }

    }

    public String getCodeOfMRVD(String Order) {
        StringBuilder res = new StringBuilder();
        String order = Order.split(" ")[0];
        res.append(getCode(order));
        String R = Order.split(" ")[1].split(",")[0];
        res.append(Integer.toHexString(Integer.parseInt(R.substring(1))));
        res.append(Order.split(",")[1]);
        return res.toString();
    }
    private String regExTwoParameter = "^[0-9A-F]{2}";
    private Pattern patternTwoParameter = Pattern.compile(regExTwoParameter, Pattern.CASE_INSENSITIVE);
    private String regExOneParameter = "^[0-9A-F]{1}";
    private Pattern patternOneParameter = Pattern.compile(regExOneParameter, Pattern.CASE_INSENSITIVE);
    private String regExOffsetParameter = "^[0-9A-F]{1,2}$";
    private Pattern patternOffsetParameter = Pattern.compile(regExOffsetParameter, Pattern.CASE_INSENSITIVE);
    private String regExPortParameter = "^(81|80|91|90)$";
    private Pattern patternPortParameter = Pattern.compile(regExPortParameter, Pattern.CASE_INSENSITIVE);

    public String getCodeOfPortAndCALAAndJMPA(String Order) {
        StringBuilder res = new StringBuilder();
        String order = Order.split(" ")[0];
        res.append(getCode(order));
        res.append(Order.split(" ")[1]);
        return res.toString();
    }

    public String getOrderByCode(String Code, int pc) {
        StringBuilder res = new StringBuilder();
        String code = Code.substring(0, 2);
        String[] order = getOrder(code);
        if (order == null) {
            return "Code^Error";
        }
        res.append(order[0]);
        code = Code.substring(2);
        Matcher matcher;
        switch (order[2]) {
            case "R_2":
                matcher = patternTwoParameter.matcher(code);
                if (matcher.matches()) {
                    res.append("\t");
                    res.append("R");
                    res.append(Integer.toHexString(Integer.parseInt(code.substring(0, 1))));
                    res.append("\t");
                    res.append("R");
                    res.append(Integer.toHexString(Integer.parseInt(code.substring(1))));
                } else {
                    return "Code^Error";
                }
                break;
            case "R_1":
                matcher = patternOneParameter.matcher(code);
                if (matcher.matches()) {
                    res.append("\t");
                    res.append("R");
                    res.append(Integer.toHexString(Integer.parseInt(code)));
                } else {
                    return "Code^Error";
                }

                break;
            case "OFFSET":
                if (order[0].equalsIgnoreCase("CALA") || order[0].equalsIgnoreCase("JMPA")) {
                    break;
                } else {
                    matcher = patternOffsetParameter.matcher(code);
                    if (matcher.matches()) {
                        res.append("\t");
                        int offset = Integer.parseInt(code, 16);
                        int adr = ((pc & 0xff) + (offset & 0xff) + 1) & 0xff;
                        adr += (pc & 0xff00);
                        String ADR = Integer.toHexString(adr);
                        res.append(ADR);
                        break;
                    } else {
                        return "Code^Error";
                    }
                }
            case "PORT":
                matcher = patternPortParameter.matcher(code);
                if (matcher.matches()) {
                    res.append("\t");
                    res.append(code);
                    break;
                } else {
                    return "Code^Error";
                }

            case "NONE":
                break;
            default:
                return "Code^Error";
        }
        return res.toString();
    }

    public String[] getOrderAndParameterByCode(String Code) {
        String[] res = new String[3];
        String code = Code.substring(0, 2);
        String[] order = getOrder(code);
        if (order == null) {
            res[0] = "UnrecognizedCode!";
            return res;
        } else {
            res[0] = order[0];
            code = Code.substring(2);
            Matcher matcher;
            switch (order[2]) {
                case "R_2":
                    matcher = patternTwoParameter.matcher(code);
                    if (matcher.matches()) {
                        res[1] = code.substring(0, 1);
                        res[2] = code.substring(1);
                    } else {
                        res[0] = "UnrecognizedCode!";
                        return res;
                    }
                    break;
                case "R_1":
                    matcher = patternOneParameter.matcher(code);
                    if (matcher.matches()) {
                        res[1] = code;
                    } else {
                        res[0] = "UnrecognizedCode!";
                        return res;
                    }
                    break;
                case "OFFSET":
                    if (order[0].equalsIgnoreCase("CALA") || order[0].equalsIgnoreCase("JMPA")) {
                        break;
                    } else {
                        matcher = patternOffsetParameter.matcher(code);
                        if (matcher.matches()) {
                            res[1] = code;
                            break;
                        } else {
                            res[0] = "UnrecognizedCode!";
                            return res;
                        }
                    }
                case "PORT":
                    matcher = patternPortParameter.matcher(code);
                    if (matcher.matches()) {
                        res[1] = code;
                        break;
                    } else {
                        res[0] = "UnrecognizedCode!";
                        return res;
                    }

                case "NONE":
                    break;
                default:
                    res[0] = "UnrecognizedCode!";
                    return res;
            }
            return res;
        }
    }

}
